﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.Xml.Serialization;

namespace SuperCalculator
{
    public partial class frmMain : Form
    {
        private ButtonsLayoutPanel panelLayoutBtn = new ButtonsLayoutPanel();
        private Button currentRightClickButton; //记录最后被右击的按钮
        //用于保存表达式,表达式中的一个小单位为一个元素
        //比如sin(53+6)的小单位分别为sin, (, 5, 3, +, 6, )
        private StringCollection cSharpMathExpressCollection = new StringCollection();

        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            LoadFunctionButtons();
            UpdateFunctionDll();
        }

        private void LoadFunctionButtons()
        {
            //添加一个按钮布局面板
            pnlFunctionButtons.Controls.Add(panelLayoutBtn);
            panelLayoutBtn.Dock = DockStyle.Fill;

            //反序列化列表文件
            var serializer = new XmlSerializer(typeof (FunctionInfoCollection));
            var sr = new StreamReader(Function.PathOfFunctionsListFile);

            FunctionInfoCollection fc;
            try
            {
                fc = (FunctionInfoCollection) serializer.Deserialize(sr);
            }
            catch (Exception ex)
            {
                MessageBox.Show("在反序列化函数列表时发生错误: \r\n" + ex);
                return;
            }
            finally
            {
                sr.Close();
            }

            foreach (FunctionInfo fi in fc)
            {
                Function.CollectionOfFunctionInfo.Add(fi);
                AddFunctionButtonToForm(fi);
            }
        }

        /// <summary>
        /// 更新函数Dll。
        /// </summary>
        private static void UpdateFunctionDll()
        {
            if (!File.Exists(Function.GetPathOfFunctionDll()))
            {
                CompilerResults res;
                CompilerUnit.BuildFunctionDll(out res);
                if (res.Errors.Count != 0)
                {
                    MessageBox.Show("生成函数失败!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            if (File.Exists(Function.GetPathOfNewFunctionDll()))
            {
                File.Copy(Function.GetPathOfNewFunctionDll(), Function.GetPathOfFunctionDll(), true);
                File.Delete(Function.GetPathOfNewFunctionDll());
            }
        }

        /// <summary>
        /// 按照FunctionInfo添加函数按钮到窗口。
        /// </summary>
        /// <param name="fi">该按钮关联的FunctionInfo对象。</param>
        public void AddFunctionButtonToForm(FunctionInfo fi)
        {
            var functionButton = new Button
            {
                Tag = fi,
                Text = fi.Name, 
                FlatStyle = FlatStyle.System
            };
            functionButton.MouseDown += functionButton_MouseDown;
            panelLayoutBtn.AddButton(ref functionButton);
        }

        /// <summary>
        /// 设置数学表达式对应的C#表达式。
        /// </summary>
        /// <param name="txt">文本。</param>
        /// <param name="append">是否追加, 若为false则为覆盖。</param>
        private void SetCSharpMathExpress(string txt, bool append)
        {
            if (!append) cSharpMathExpressCollection.Clear();
            cSharpMathExpressCollection.Add(txt);
        }

        /// <summary>
        /// 向输入文本框中添加文本。
        /// </summary>
        /// <param name="txt">要添加的文本。</param>
        /// <param name="append">是否追加。</param>
        /// <param name="txtColor">文本的颜色。</param>
        private void Input(string txt, bool append, Color txtColor)
        {
            if (!append) richTextBoxInput.Clear();
            var oldPos = richTextBoxInput.SelectionStart;
            richTextBoxInput.AppendText(txt);
            var newPos = richTextBoxInput.SelectionStart;
            richTextBoxInput.SelectionStart = oldPos;
            richTextBoxInput.SelectionLength = txt.Length;
            richTextBoxInput.SelectionColor = txtColor;

            richTextBoxInput.SelectionStart = newPos;
        }

        /// <summary>
        /// 向输出文本框中添加文本。
        /// </summary>
        /// <param name="txt">要添加的文本。</param>
        /// <param name="append">是否追加。</param>
        /// <param name="txtColor">文本的颜色。</param>
        private void Output(string txt, bool append, Color txtColor)
        {
            if (!append) richTextBoxOutput.Clear();
            var oldPos = richTextBoxOutput.SelectionStart;
            richTextBoxOutput.AppendText(txt);
            var newPos = richTextBoxOutput.SelectionStart;
            richTextBoxOutput.SelectionStart = oldPos;
            richTextBoxOutput.SelectionLength = txt.Length;
            richTextBoxOutput.SelectionColor = txtColor;

            richTextBoxOutput.SelectionStart = newPos;
        }


        void functionButton_MouseDown(object sender, MouseEventArgs e)
        {
            var bt = (Button) sender;
            var fInfo = (FunctionInfo) bt.Tag;

            if (e.Button == MouseButtons.Left)
            {
                Input(fInfo.Name, true, Color.Green); //添加到输入文本框
                SetCSharpMathExpress(Function.FunctionClassName + "." + fInfo.Name, true); //添加到cSharp表达式

                //利用反射取得函数原型,并添加到输出文本框
                var dll = Function.GetPathOfFunctionDll();
                if (File.Exists(dll))
                {
                    try
                    {
                        var ass = Assembly.LoadFile(dll);
                        var t = ass.GetType("FunctionNameSpace.FunctionClass");
                        var mi = t.GetMethod(fInfo.Name);
                        Output(mi.ToString(), false, Color.Green);
                    }
                    catch { }
                }
                //显示提示信息
                Output(Environment.NewLine + fInfo.ExplainInfo, true, Color.Green);

                //自动添加左括号
                DigitalButtonDown(btnLeftBracket, e);
            }
            else if (e.Button == MouseButtons.Right)
            {
                currentRightClickButton = (Button) sender;
                contextMenuStripOfFunctionButton.Show(bt, e.Location);
            }
        }

        //上下文菜单: 编辑此函数
        private void mnuEditFunction_Click(object sender, EventArgs e)
        {
            if (currentRightClickButton == null) return;
            var fInfo = this.currentRightClickButton.Tag as FunctionInfo;
            if (fInfo == null) return;
            var fc = new frmFunctionCoding(fInfo, false);
            fc.ShowDialog(this);
        }

        //上下文菜单: 删除此函数
        private void mnuDeleteFunction_Click(object sender, EventArgs e)
        {
            if (currentRightClickButton == null) return;
            var fInfo = currentRightClickButton.Tag as FunctionInfo;
            if (fInfo == null) return;
            var warning = "注意! 此操作将删除函数: " + fInfo.Name + "\r\n" +
                          "及其关联的代码文件: " + Function.DirectoryOfFunctions + fInfo.RelativePathOfCodeFile + "\r\n" +
                          "确实要删除吗?";
            if (MessageBox.Show(warning, "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)
                != DialogResult.OK) return;

            //删除
            try
            {
                Function.CollectionOfFunctionInfo.Remove(fInfo);
                File.Delete(Function.DirectoryOfFunctions + fInfo.RelativePathOfCodeFile);
            }
            catch { }

            //保存
            Function.SaveFunctionsToList();

            //重新绘制函数按钮
            panelLayoutBtn.Controls.Clear();
            for (var i = 0; i < Function.CollectionOfFunctionInfo.Count; i++)
            {
                var fi = Function.CollectionOfFunctionInfo[i];
                AddFunctionButtonToForm(fi);
            }
        }

        //添加函数
        private void btnAddFunction_Click(object sender, EventArgs e)
        {
            var frmGuide = new frmAddFunctionGuide();
            if (frmGuide.ShowDialog(this) != DialogResult.OK) return;

            var functionName = frmGuide.FunctionName;
            var pathOfCodeFile = Function.GetRelativePathOfFunctionCodeFile(functionName);
            var info = frmGuide.ExplainInfo;

            var fInfo = new FunctionInfo(functionName, pathOfCodeFile, info);
            var frmCode = new frmFunctionCoding(fInfo, true);

            frmCode.ShowDialog(this);
        }

        //数字按钮事件处理
        private void DigitalButtonDown(object sender, MouseEventArgs e)
        {
            var bt = (Button) sender;
            if (e.Button == MouseButtons.Left)
            {
                Input(bt.Text, true, Color.Blue);
                SetCSharpMathExpress(bt.Text, true);
            }
        }

        //操作符按钮事件处理
        private void OperatorButtonDown(object sender, MouseEventArgs e)
        {
            var bt = (Button) sender;
            if (e.Button == MouseButtons.Left)
            {
                Input(" " + bt.Text + " ", true, Color.Red);
                SetCSharpMathExpress(" " + bt.Text + " ", true);
            }
        }

        private void btnEqual_Click(object sender, EventArgs e)
        {
            //表达式
            var express = "";
            foreach (var s in cSharpMathExpressCollection)
            {
                express += s;
            }
            var source = TranslateUnit.TranslateToCSharp(express);

            //这里加载了函数dll
            var dlls = new string[1];
            dlls[0] = Function.GetPathOfFunctionDll();
            var results = CompilerUnit.Compile(source, false, true, dlls, null);

            //重要: 利用反射获取计算结果
            if (results.Errors.Count == 0)
            {
                var ass = results.CompiledAssembly;
                var tp = ass.GetType("ComputeUnit.Compute");//ass.GetType("MyNamespace.MyClass");

                // 获取方法
                var mi = tp.GetMethod("GetResult");//tp.GetMethod("MyMethodl");

                // 创建实例
                var obj = Activator.CreateInstance(tp);

                //执行方法
                try
                {
                    var res = mi.Invoke(obj, null);
                    Output(res.ToString(), false, Color.Blue);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                var errMsg = "表达式错误:" + Environment.NewLine;
                foreach (CompilerError err in results.Errors)
                {
                    errMsg += err.ErrorText + Environment.NewLine;
                }
                Output(errMsg, false, Color.Red);
            }
        }

        private void btnBackspace_Click(object sender, EventArgs e)
        {
            //undo输入框中最近操作
            //这里的richTextBoxInput.Undo次数取决于Input()函数中对richTextInput的操作次数
            richTextBoxInput.Undo();
            richTextBoxInput.Undo();

            //移出表达式中最近加入的元素
            if (cSharpMathExpressCollection.Count > 0)
            {
                cSharpMathExpressCollection.RemoveAt(cSharpMathExpressCollection.Count - 1);
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            Input("", false, Color.Black);
            Output("", false, Color.Black);
            SetCSharpMathExpress("", false);
        }

        private void btnPI_Click(object sender, EventArgs e)
        {
            Input("PI", true, Color.Blue);
            SetCSharpMathExpress(" " + Math.PI + " ", true);
        }

        private void btnE_Click(object sender, EventArgs e)
        {
            Input("E", true, Color.Purple);
            SetCSharpMathExpress(" " + Math.E + " ", true);
        }

        private void btnNum5_Click(object sender, EventArgs e)
        {

        }
    }
}
